<template>
  <div>
    <el-dialog v-model="dialogVisible" fullscreen>
      <div class="media-preview-container">
        <div class="left-panel relative">
          <div v-if="isPanorama" class="h-full w-full">
            <div ref="panorama"></div>
          </div>
          <div v-else-if="isImage" id="viewerContainer" v-viewer="options">
            <img :src="mediaUrl" alt="可缩放图片" style="object-fit: cover; cursor: grab; display: none" />
          </div>
          <div v-else-if="isVideo" class="video-wrapper">
            <video
              ref="videoPlayer"
              class="video-js"
              @loadedmetadata="handleVideoLoaded"
              :src="mediaUrl"
              controls
              style="object-fit: contain"
            ></video>
          </div>
          <div v-else>无法显示该类型的文件</div>
          <div class="mask">
            <div class="photo-name">
              <span class="text-white">{{ mediaInfo.file_name.split('.')[0] }}</span>
            </div>
            <div class="detail">
              <div class="flex gap-3">
                <Clock3 />
                <span>
                  {{ mediaInfo.create_time }}
                </span>
                <span>
                  {{ file_size }}
                </span>
                <span>
                  {{ mediaInfo.resolution }}
                </span>
              </div>
            </div>
          </div>
        </div>

        <div class="right-panel">
          <div class="detail-header">
            <span>详细信息</span>
            <X class="el-icon-close cursor-pointer" @click="dialogVisible = false"></X>
          </div>
          <div class="detail-content flex flex-col">
            <span class="column"
              ><span class="name">文件名称</span> <span class="desc">{{ mediaInfo.file_name.split('.')[0] }}</span></span
            >
            <span class="column"
              ><span class="name"> 文件类型</span> <span class="desc">{{ mediaInfo.mediaType }}</span></span
            >
            <span class="column">
              <span class="name">任务名称</span>
              <span class="desc">
                {{ mediaInfo.job_name }}
              </span>
            </span>
            <span class="column" v-if="!isVideo">
              <span class="name">分辨率</span>
              <span class="desc">
                {{ mediaInfo.resolution }}
              </span>
            </span>
            <span class="column" v-if="isImage">
              <span class="name">文件大小</span>
              <span class="desc">
                {{ mediaInfo.fileSize }}
              </span>
            </span>
            <span class="column" v-if="isVideo">
              <span class="name">视频时长</span>
              <span class="desc"> {{ mediaInfo.duration }} s </span>
            </span>
            <span class="column" v-if="isVideo">
              <span class="name">视频分辨率</span>
              <span class="desc">
                {{ mediaInfo.resolution }}
              </span>
            </span>
            <span class="column" v-if="isVideo">
              <span class="name">视频大小</span>
              <span class="desc">
                {{ mediaInfo.fileSize }}
              </span>
            </span>

            <span class="column">
              <span class="name">拍摄时间</span>
              <span class="desc">
                {{ mediaInfo.create_time }}
              </span>
            </span>
            <span class="column" v-if="!isVideo">
              <span class="name"> 纬度 </span>
              <span class="desc">
                {{ mediaInfo.latitude }}
              </span>
            </span>
            <span class="column" v-if="!isVideo">
              <span class="name"> 经度 </span>
              <span class="desc">
                {{ mediaInfo.longitude }}
              </span>
            </span>
            <span class="column" v-if="!isVideo">
              <span class="name"> 高度 </span>
              <span class="desc">
                {{ mediaInfo.altitude }}
              </span>
            </span>
          </div>
          <div>
            <div v-if="isImage" ref="refMap" style="height: 250px; width: 100%"></div>
          </div>
        </div>
      </div>
      <div class="bottom-panel">
        <div class="flex justify-center gap-2 py-4">
          <div
            v-for="item in mediaList"
            :key="item.file_id"
            class="img-preview relative"
            :class="{ 'active-media': item.file_id === mediaInfo.file_id }"
            @click="handlePreview(item)"
          >
            <template v-if="isImage || isPanorama">
              <img :src="item.signed_url" alt="可缩放图片" style="object-fit: cover; cursor: grab" />
            </template>
            <template v-else-if="isVideo">
              <img :src="item.signed_url" style="object-fit: contain; cursor: grab" />
            </template>
            <div class="img-preview-type justify-center items-center" v-if="checkMediaType(item).isPanorama">
              <img src="@/assets/icons/panorama.svg" alt="" />
            </div>
            <div class="img-preview-type top-0 right-0" v-if="checkMediaType(item).isImage">
              {{ getMediaType(item.photo_type) }}
            </div>
            <div class="img-preview-type" v-if="checkMediaType(item).isVideo">
              <Play />
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import * as L from 'leaflet'
import 'leaflet/dist/leaflet.css'
// import { pannellum } from 'pannellum'
import 'leaflet.chinatmsproviders'
import { Clock3, Play, X } from 'lucide-vue-next'
import { computed, ref } from 'vue'
import { ElLoadingInstance, IMedia, MediaTypeMap } from '../types/media'
import { getUrlToBase64 } from '../utils/common'

interface Props {
  visible: boolean
  mediaInfo: IMedia
  mediaUrl: string
  mediaList: IMedia[]
}

const refMap = ref<HTMLDivElement | null>(null)
const loading = ref(true)
// 在组件顶部定义持久化变量
let mapInstance: L.Map | null = null
let markerInstance: L.Marker | null = null
// const mapInstance = ref<L.Map | null>(null)
// const markerInstance = ref<L.Marker | null>(null)
const isMapInitialized = ref(false)
const TDT_KEY = 'b523cf004dc0b0eb1d6ec8bf9d381ae5'
async function updateMapContent(lat: number, lng: number, mediaInfo: IMedia) {
  try {
    // 首次初始化地图
    if (!isMapInitialized.value && refMap.value) {
      const imgm = (L.tileLayer as any).chinaProvider('TianDiTu.Satellite.Map', {
        key: TDT_KEY,
        maxZoom: 24,
        maxNativeZoom: 18,
        minZoom: 5
      })

      const imga = (L.tileLayer as any).chinaProvider('TianDiTu.Satellite.Annotion', {
        key: TDT_KEY,
        maxZoom: 24,
        maxNativeZoom: 18
      })

      mapInstance = L.map(refMap.value, {
        zoom: 18,
        maxZoom: 24,
        minZoom: 5,
        center: [lat, lng],
        zoomControl: false,
        renderer: L.canvas({ tolerance: 16 }),
        layers: [L.layerGroup([imgm, imga])],
        attributionControl: false
      })

      isMapInitialized.value = true
    }

    // 更新地图内容
    if (mapInstance) {
      // 清除旧标记
      if (markerInstance) {
        mapInstance.removeLayer(markerInstance)
      }

      // 创建新标记
      const customIcon = L.icon({
        iconUrl: await getUrlToBase64(mediaInfo.signed_url),
        iconSize: [32, 32],
        iconAnchor: [16, 32],
        className: 'custom-marker'
      })

      markerInstance = L.marker([lat, lng], { icon: customIcon }).addTo(mapInstance)

      // 更新视图中心
      mapInstance.setView([lat, lng], 18)
    }

    loading.value = false
  } catch (error) {
    console.error('地图更新失败:', error)
    loading.value = false
  }
}
// 在组件卸载时清理
onUnmounted(() => {
  if (mapInstance) {
    mapInstance.remove()
    mapInstance = null
  }
})
async function processImageFromURL() {
  try {
    const response = await fetch(mediaInfo.value.src_signed_url)
    const blob = await response.blob()

    // 创建临时URL并加载图片
    const img = new Image()
    const objectURL = URL.createObjectURL(blob)

    // 使用Promise包装图片加载
    const { naturalWidth, naturalHeight } = await new Promise<{ naturalWidth: number; naturalHeight: number }>(
      (resolve, reject) => {
        img.onload = () => {
          resolve({
            naturalWidth: img.naturalWidth,
            naturalHeight: img.naturalHeight
          })
          URL.revokeObjectURL(objectURL) // 及时释放内存
        }
        img.onerror = () => reject(new Error('图片加载失败'))
        img.src = objectURL
      }
    )

    console.log(naturalWidth, naturalHeight, '=')
    const call_back_param = mediaInfo.value.call_back_param
    const lat = call_back_param.metadata.shootPosition.lat
    const lng = call_back_param.metadata.shootPosition.lng
    const altitude = call_back_param.metadata.absoluteAltitude + ' 米'
    // 更新媒体信息
    mediaInfo.value = {
      ...mediaInfo.value,
      resolution: `${naturalWidth}x${naturalHeight}`,
      mediaType: MediaTypeMap[mediaInfo.value.photo_type] || '未知',
      latitude: call_back_param.metadata.shootPosition.lat,
      longitude: call_back_param.metadata.shootPosition.lng,
      altitude: call_back_param.metadata.absoluteAltitude + ' 米',
      fileSize: formatFileSize(mediaInfo.value.file_size)
    }
    await updateMapContent(lat, lng, mediaInfo.value)
  } catch (error) {
    console.error('图片处理失败:', error)
    alert('图片加载失败，请检查链接有效性及跨域设置')
  }
}
const handlePreview = (item: IMedia) => {
  mediaInfo.value = item
  mediaUrl.value = item.src_signed_url
  init()
}
const handleDialogClose = (done: () => void) => {
  done()
}
const handleVideoPlay = () => {
  if (videoPlayer.value) {
    videoPlayer.value.play()
  }
}
const handleVideoPause = () => {}
// 使用示例
const videoPlayer = ref<HTMLVideoElement | null>(null)
function formatFileSize(fileSize: number) {
  const units = ['KB', 'MB', 'GB', 'TB']
  let index = 0

  while (fileSize >= 1024 && index < units.length - 1) {
    fileSize /= 1024
    index++
  }
  return fileSize.toFixed(1) + ' ' + units[index]
}
// 写一个函数,传入一个值，判断是红外，变焦还是广角
const getMediaType = (photo_type: number) => {
  switch (photo_type) {
    case 1:
      return 'W'
    case 2:
      return 'Z'
    case 3:
      return 'IR'
  }
}
const props = defineProps<Props>()
const dialogVisible = useModel(props, 'visible')

const mediaInfo = useModel(props, 'mediaInfo') // 媒体文件信息
const mediaUrl = useModel(props, 'mediaUrl') // 媒体文件地址
const file_size = computed(() => formatFileSize(props.mediaInfo.file_size))
const mediaList = useModel(props, 'mediaList') // 媒体文件列表
const options = {
  container: '#viewerContainer',
  backdrop: false,
  button: true,
  navbar: false,
  toolbar: false,
  tooltip: true,
  title: false,
  inline: true,
  oneToOne: true,
  play: true,
  images: [mediaUrl.value]
}

const pannellum = (window as Record<string, any>).pannellum
// 支持更多媒体类型
enum MediaTypes {
  Image = 1,
  Video = 2,
  Audio = 3,
  Document = 4
}

// 增强版判断函数
const checkMediaType = (params: IMedia) => ({
  isImage: params.media_type === MediaTypes.Image && params.sub_file_type === 0,
  isVideo: params.media_type === MediaTypes.Video,
  isPanorama: params.sub_file_type === 1,
  isAudio: params.media_type === MediaTypes.Audio,
  isDocument: params.media_type === MediaTypes.Document
})
// 判断是否是图片
const isImage = computed(() => {
  return mediaInfo.value?.media_type === 1 && mediaInfo.value?.sub_file_type === 0
})

// 判断是否是视频
const isVideo = computed(() => {
  return mediaInfo.value?.media_type === 2
})
// 判断是不是全景
const isPanorama = computed(() => {
  return mediaInfo.value?.sub_file_type === 1
})
const panorama = ref<HTMLElement | null>(null)
const init = async () => {
  console.log(props.mediaInfo)
  if (checkMediaType(mediaInfo.value).isPanorama) {
    pannellum.viewer(panorama.value, {
      type: 'equirectangular',
      autoLoad: true,
      panorama: mediaInfo.value.src_signed_url
    })
  }
  if (!isVideo.value) {
    processImageFromURL()
    const call_back_param = props.mediaInfo.call_back_param
    mediaInfo.value = {
      ...mediaInfo.value,
      // resolution: allMetaData.PixelXDimension + 'x' + allMetaData.PixelYDimension,
      // file_size: file.size,
      mediaType: MediaTypeMap[mediaInfo.value.photo_type] || '未知',
      latitude: call_back_param.metadata.shootPosition.lat,
      longitude: call_back_param.metadata.shootPosition.lng,
      altitude: call_back_param.metadata.absoluteAltitude + ' 米'
    }
    loading.value = false
  }
}
const handleVideoLoaded = () => {
  if (videoPlayer.value) {
    mediaInfo.value = {
      ...mediaInfo.value,
      resolution: videoPlayer.value.videoWidth + 'x' + videoPlayer.value.videoHeight,
      duration: videoPlayer.value.duration.toFixed(2),
      mediaType: MediaTypeMap[mediaInfo.value.photo_type] || '未知',
      fileSize: formatFileSize(mediaInfo.value.file_size)
    }
    loading.value = false
  }
}
onMounted(() => {
  openFullScreen2()
  nextTick(async () => {
    await init()
  })
})
const loadingApi = ref<ElLoadingInstance | null>(null)
watch(
  () => loading.value,
  (val) => {
    if (!val) {
      console.log('loading', val)
      loadingApi.value!.close()
    }
  },
  { deep: true }
)
const openFullScreen2 = () => {
  loadingApi.value = ElLoading.service({
    lock: true,
    text: '加载数据中...'
  })
}
</script>

<style scoped lang="scss">
.media-preview-container {
  display: flex;
  height: 88%;
  gap: 10px;
}

.left-panel {
  flex: 2;
}
.bottom-panel {
  background-color: rgba(65, 64, 64, 0.7);
}

.right-panel {
  padding: 20px;
  background-color: rgba(65, 64, 64, 0.7);
  border-left: 1px solid #000;
  width: 420px;
}

.image-wrapper {
  width: 100%;
  height: 740px;
  img {
    height: 100%;
    width: 100%;
  }
}

.video-wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  video {
    width: 100%;
    height: 100%;
  }
}

.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.detail-content {
  padding: 20px;
}
:deep(.el-dialog__header) {
  display: none !important;
}
:deep(.el-dialog__body) {
  height: 100% !important;
  box-sizing: border-box !important;
}
.mask {
  background-image: linear-gradient(179deg, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.08) 71%, transparent 100%);
  width: 100%;
  padding: 16px 0 16px 24px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 9999;
  .photo-name {
    pointer-events: all;
    align-items: center;
    padding: 0 70px 0 0;
    font-size: 20px;
    font-weight: 700;
    line-height: 32px;
    display: flex;
  }
  .detail {
    font-size: 14px;
    line-height: 24px;
  }
}
.name {
  color: rgba(255, 255, 255, 0.45);
  flex-shrink: 0;
  width: 70px;
  line-height: 16px;
}
.desc {
  color: #fff;
  width: 293px;
  margin-left: 16px;
  position: relative;
  overflow: hidden;
}
.column {
  flex: none;
  align-items: center;
  height: 38px;
  font-size: 14px;
  display: flex;
}
#refMap {
  height: 300px;
  width: 100%;
}
:deep(.pnlm-zoom-controls) {
  bottom: 60px !important;
  right: 20px !important;
  position: fixed !important;
}
:deep(.pnlm-fullscreen-toggle-button) {
  bottom: 20px !important;
  position: fixed !important;
  right: 20px !important;
}
.img-preview {
  cursor: pointer;
  opacity: 0.5;
  border-radius: 4px;
  justify-content: center;
  align-items: center;
  width: 100px;
  min-width: 100px;
  height: 80px;
  display: flex;
  position: relative;
  overflow: hidden;
  &:hover {
    opacity: 1;
  }
  .img-preview-type {
    z-index: 1;
    color: #fff;
    background: rgba(0, 0, 0, 0.3);
    justify-content: center;
    align-items: center;
    width: 24px;
    height: 24px;
    line-height: 24px;
    display: flex;
    position: absolute;
  }
}
.active-media {
  border: 2px solid #1088f2;
  box-shadow: 0 2px 8px rgba(16, 136, 242, 0.2);
  opacity: 1;
}
</style>
